home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / rename-files < prev    next >
Encoding:
Internet Message Format  |  1989-03-12  |  17.6 KB

  1. Subject:  v18i022:  Rename multiple files
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Vladimir Lanin <lanin@csd2.nyu.edu>
  7. Posting-number: Volume 18, Issue 22
  8. Archive-name: rename-files
  9.  
  10. This must have been done already by someone somewhere, but I could not
  11. find it, so here goes.
  12.  
  13. Whereas mv can rename (as opposed to move) only one file at a time, the
  14. following program (ren) can rename many files according to search and
  15. replacement patterns, ala VMS (but better).  ren checks for replacement
  16. name collisions and handles rename chains gracefully.
  17.  
  18. To compile, just unshar the following and cc ren.c.  ren.1 contains the
  19. man style doc.
  20.  
  21. I have not tried this under anything but bsd 4.2 and 4.3, but I don't see
  22. why there should be a problem.
  23.  
  24. Vladimir Lanin
  25. lanin@csd2.nyu.edu
  26.  
  27. Any comments appreciated.
  28.  
  29. --cut here--
  30. #! /bin/sh
  31. # This is a shell archive, meaning:
  32. # 1. Remove everything above the #! /bin/sh line.
  33. # 2. Save the resulting text in a file.
  34. # 3. Execute the file with /bin/sh (not csh) to create:
  35. #    Makefile (spliced in by hand)
  36. #    ren.1
  37. #    ren.c
  38. export PATH; PATH=/bin:/usr/bin:$PATH
  39. echo shar: 'extracting Makefile'
  40. if test -f Makefile ; then
  41.     echo shar: will not clobber existing Makefile
  42. else
  43. sed 's/^X//' <<\SHAR_EOF >Makefile
  44. Xall:    ren ren.1
  45. X
  46. Xren:    ren.c
  47. X    $(CC) -o ren $(CFLAGS) ren.c
  48. Xinstall:    all
  49. X    @echo "install according to local convention"
  50. Xclean:
  51. X    rm -f core a.out ren ren.o
  52. SHAR_EOF
  53. fi
  54. echo shar: "extracting 'ren.1'" '(3843 characters)'
  55. if test -f 'ren.1'
  56. then
  57.     echo shar: "will not over-write existing file 'ren.1'"
  58. else
  59. sed 's/^X//' << \SHAR_EOF > 'ren.1'
  60. X.TH REN 1 "May 20, 1988"
  61. X.UC 4
  62. X.SH NAME
  63. Xren \- rename multiple files
  64. X.SH SYNOPSIS
  65. X.B ren
  66. X[
  67. X.B \-d
  68. X|
  69. X.B \-k
  70. X|
  71. X.B \-a
  72. X] [
  73. X.B \-v
  74. X] [path/]search replacement
  75. X.SH DESCRIPTION
  76. X.I Ren
  77. Xrenames each file in the current directory
  78. X(or in the
  79. X.I path
  80. Xdirectory, if specified)
  81. Xthat matches the
  82. X.I search
  83. Xpattern;
  84. Xeach matching file's new name is given by the
  85. X.I replacement
  86. Xpattern.
  87. XThe multiple rename is performed safely,
  88. Xi.e. without any unexpected deletion of files
  89. Xdue to collisions of replacement names with existing names,
  90. Xor with other replacement names.
  91. XAlso, all error checking is done prior to doing any renames,
  92. Xso either all renames are done, or none.
  93. X.PP
  94. XThe search pattern is a filename
  95. Xwith embedded wildcards, i.e. * and ?,
  96. Xwhich have their usual meanings of, respectively,
  97. Xmatching any string of characters,
  98. Xand matching any single character.
  99. XThe replacement pattern is another filename
  100. Xwith embedded
  101. X.I wildcard
  102. X.IR indexes ,
  103. Xeach of which consists of the character # followed by a digit
  104. Xfrom 1 to 9.
  105. XIn the new name of a matching file,
  106. Xthe wildcard indexes are replaced by the
  107. Xactual characters that matched the referenced wildcards
  108. Xin the original filename.
  109. XThus, if the search pattern is "abc*.*.*"
  110. Xand the replacement pattern is "xyz#1.#3",
  111. Xthen "abc.txt.doc" is renamed to "xyz.doc"
  112. X(since the first * matched "", the second matched "txt",
  113. Xand the third matched "doc").
  114. X.PP
  115. XNote that the shell normally expands the wildcards * and ?,
  116. Xwhich in the case of
  117. X.I ren
  118. Xis undesirable.
  119. XThus, in most cases it is necessary to enclose the search pattern
  120. Xin quotes, e.g.
  121. Xren "*.a" #1.b.
  122. XTo strip any of the characters *, ?, and # of their special meaning to
  123. X.I ren,
  124. Xas when the actual replacement name must contain the character #,
  125. Xprecede the special character with \\
  126. X(and enclose the argument in qoutes because of the shell).
  127. X.PP
  128. XNote that a path is not allowed in the replacement pattern.
  129. X.I Ren
  130. Xdoes not allow moving files between directories,
  131. Xwhich facilitates the safety checks next described.
  132. X.PP
  133. XWhen any two matching files
  134. Xwould have to be renamed to the same new filename,
  135. X.I ren
  136. Xdetects the condition prior to doing any renames
  137. Xand aborts with an error message.
  138. X.pp
  139. X.I Ren
  140. Xalso checks if any file deletes would result from the rename,
  141. Xi.e. if some file1 would have to be renamed to file2,
  142. Xand file2 already exists and is not itself being renamed.
  143. X(Here and below, "delete" really means "unlink".)
  144. XIn such a case,
  145. X.I ren
  146. Xasks you (by reading a line from standard input)
  147. Xif you really wish file2 to be deleted.
  148. XIf your answer is negative, file1 is not renamed.
  149. X.PP
  150. X.I Ren
  151. Xsafely performs chain renames,
  152. Xi.e. when file1 is renamed to file2,
  153. Xfile2 to file3, file3 to file4, etc,
  154. Xby doing the renames in the proper order.
  155. XIn the case that the chain is a cycle, i.e. filen is renamed back to file1,
  156. X.I ren
  157. Xbreaks the cycle by using a temporary name.
  158. X.PP
  159. XFiles beginning with . are not matched against the search pattern
  160. X(and thus not renamed)
  161. Xunless the search pattern explicitly begins with '.'.
  162. XIn any case, "." and ".." are never matched.
  163. X.PP
  164. XOptions:
  165. X.TP
  166. X.I \-v
  167. X(verbose):
  168. Xafter each rename,
  169. Xthe message "file1 -> file2 [(*)]" appears on the standard output.
  170. XThe (*) appears in the case of a deleting rename,
  171. Xi.e. when the old file2 is deleted.
  172. X.TP
  173. X.IR \-d ,
  174. X.IR \-k ,
  175. X.IR \-a :
  176. Xsuppress interrogation with regard to deleting renames, and:
  177. X.TP
  178. X.I \-d
  179. X(delete): perform all deleting renames silently.
  180. X.TP
  181. X.I \-k
  182. X(keep): perform no deleting renames.
  183. X.TP
  184. X.I \-a
  185. X(abort): if any deleting renames are detected,
  186. Xabort prior to doing any renames.
  187. X.SH "SEE ALSO"
  188. Xmv(1)
  189. X.SH "AUTHOR"
  190. XVladimir Lanin
  191. X.br
  192. Xlanin@csd2.nyu.edu
  193. X.SH "BUGS"
  194. XIf the search pattern is not quoted,
  195. Xthe shell expands the wildcards.
  196. X.I Ren
  197. Xthen complains that there are too many arguments
  198. X(if indeed there are),
  199. Xbut can not determine that the lack of quotes is the cause.
  200. SHAR_EOF
  201. if test 3843 -ne "`wc -c < 'ren.1'`"
  202. then
  203.     echo shar: "error transmitting 'ren.1'" '(should have been 3843 characters)'
  204. fi
  205. fi
  206. echo shar: "extracting 'ren.c'" '(11365 characters)'
  207. if test -f 'ren.c'
  208. then
  209.     echo shar: "will not over-write existing file 'ren.c'"
  210. else
  211. sed 's/^X//' << \SHAR_EOF > 'ren.c'
  212. X#include <stdio.h>
  213. X#include <sys/file.h>
  214. X#include <sys/types.h>
  215. X#include <sys/dir.h>
  216. X
  217. X#define MAXWILD 20
  218. X#define MAXREP 40
  219. X
  220. Xtypedef struct rep{
  221. X    int ftorep;
  222. X    char *repname;
  223. X    struct rep *dofirst;
  224. X    int mustdel;
  225. X    int status;
  226. X    struct rep *nextrep;
  227. X} REP;
  228. X
  229. X#define DO 0
  230. X#define FORGET 1
  231. X#define DONE 2
  232. X
  233. X#define ASKDEL 0
  234. X#define QUIETDEL 1
  235. X#define NODEL 2
  236. X#define ABORTDEL 3
  237. X
  238. Xextern int alphasort();
  239. Xextern int scandir();
  240. Xextern qsort();
  241. X
  242. Xstatic procargs();
  243. Xstatic int procdir();
  244. Xstatic int checkpats();
  245. Xstatic int getreps();
  246. Xstatic int scan();
  247. Xstatic char *makerep();
  248. Xstatic checkcollisons();
  249. Xstatic int mycmp();
  250. Xstatic checkdeletes();
  251. Xstatic int bsearch();
  252. Xstatic char** breakcycles();
  253. Xstatic dorenames();
  254. X
  255. Xstatic char tempprefix[] = "renTMP";
  256. X
  257. Xmain(argc, argv)
  258. X    int argc;
  259. X    char *(argv[]);
  260. X{
  261. X    char *from_pat, *to_pat, *path;
  262. X    int verbose, delstyle;
  263. X    int nfils, nreps;
  264. X    struct direct **dot;
  265. X    REP *reps, **filrep;
  266. X    char **tempnames;
  267. X
  268. X    procargs(argc, argv, &verbose, &delstyle, &from_pat, &to_pat, &path);
  269. X    checkpats(from_pat, to_pat);
  270. X    nfils = procdir(path, &dot, &filrep);
  271. X    nreps = getreps(dot, nfils, from_pat, to_pat, filrep, &reps);
  272. X    checkcollisons(reps, nreps);
  273. X    checkdeletes(reps, dot, filrep, nfils, delstyle);
  274. X    tempnames = breakcycles(reps, nreps, dot);
  275. X    dorenames(reps, dot, tempnames, verbose);
  276. X    return(0);
  277. X}
  278. X
  279. X
  280. Xstatic procargs(argc, argv, pverbose, pdelstyle, pfrom_pat, pto_pat, ppath)
  281. X    int argc;
  282. X    char *(argv[]);
  283. X    int *pverbose, *pdelstyle;
  284. X    char **pfrom_pat, **pto_pat, **ppath;
  285. X{
  286. X    char *p;
  287. X    int arg1;
  288. X
  289. X    *pverbose = 0;
  290. X    *pdelstyle = ASKDEL;
  291. X    for (arg1 = 1; arg1 < argc && *(argv[arg1]) == '-'; arg1++)
  292. X        for (p = argv[arg1]+1; *p != '\0'; p++)
  293. X            if (*p == 'v')
  294. X                *pverbose = 1;
  295. X            else if (*p == 'd')
  296. X                *pdelstyle = QUIETDEL;
  297. X            else if (*p == 'k')
  298. X                *pdelstyle = NODEL;
  299. X            else if (*p == 'a')
  300. X                *pdelstyle = ABORTDEL;
  301. X            else {
  302. X                fputs("Illegal option -", stderr);
  303. X                fputc(*p, stderr);
  304. X                fputc('\n', stderr);
  305. X                exit(1);
  306. X            }
  307. X
  308. X    if (argc - arg1 != 2) {
  309. X        fputs(
  310. X            "Usage: ren [-d|-k|-a] [-v] [path/]search_pattern replacement_pattern\n",
  311. X            stderr);
  312. X        fputs("\nSearch patterns containing wildcard(s) should be quoted.\n",
  313. X            stderr);
  314. X        fputs("Put #n into the replacement pattern to insert the string\n",
  315. X            stderr);
  316. X        fputs("matched by the n'th wildcard in the search pattern.\n", stderr);
  317. X        exit(1);
  318. X    }
  319. X
  320. X    *ppath = argv[arg1];
  321. X    *pto_pat = argv[arg1 + 1];
  322. X    for (
  323. X        *pfrom_pat = *ppath + strlen(*ppath);
  324. X        **pfrom_pat != '/' && *pfrom_pat != *ppath;
  325. X        --(*pfrom_pat)
  326. X    ) {}
  327. X    if (**pfrom_pat == '/') {
  328. X        **pfrom_pat = '\0';
  329. X        if (*pfrom_pat == *ppath)
  330. X            *ppath = "/";
  331. X        (*pfrom_pat)++;
  332. X    }
  333. X    else
  334. X        *ppath = ".";
  335. X}
  336. X
  337. X
  338. Xstatic checkpats(from_pat, to_pat)
  339. X    char *from_pat, *to_pat;
  340. X{
  341. X    char *p;
  342. X    int nwilds;
  343. X
  344. X    for (nwilds = 0, p = from_pat; *p != '\0'; p++) {
  345. X        if (*p == '\\') {
  346. X            p++;
  347. X            if (*p == '\0')
  348. X                break;
  349. X        }
  350. X        else if (*p == '*' || *p == '?')
  351. X            nwilds++;
  352. X    }
  353. X
  354. X    for (p = to_pat; *p != '\0'; p++) {
  355. X        if (*p == '/') {
  356. X            fputs("The replacement pattern must not contain a path.\n",
  357. X                stderr);
  358. X            exit(1);
  359. X        }
  360. X        else if (*p == '*' || *p == '?') {
  361. X            fputs("No wildcards allowed in replacement pattern.\n", stderr);
  362. X            fputs("Use #n to insert the substring matched\n", stderr);
  363. X            fputs("by the n'th wildcard in the search pattern.\n", stderr);
  364. X            exit(1);
  365. X        }
  366. X        else if (*p == '#') {
  367. X            if (*(p+1) < '1' || *(p+1) > '9' || *(p+1) - '0' > nwilds) {
  368. X                fputc('#', stderr);
  369. X                fputc(*(p+1), stderr);
  370. X                fputs(": bad substring numer.\n", stderr);
  371. X                fputs("(Use '\\#' to get '#' in replacement string.)\n", stderr);
  372. X                exit(1);
  373. X            }
  374. X            p++;
  375. X        }
  376. X        else if (*p == '\\') {
  377. X            p++;
  378. X            if (*p == '\0')
  379. X                break;
  380. X        }
  381. X    }
  382. X}
  383. X
  384. X
  385. Xstatic int procdir(path, pdot, pfilrep)
  386. X    char *path;
  387. X    struct direct ***pdot;
  388. X    REP ***pfilrep;
  389. X{
  390. X    int nfils;
  391. X
  392. X    if (access(path, R_OK | X_OK | W_OK) < 0) {
  393. X        fputs("Read/write access denied to ", stderr);
  394. X        fputs(path, stderr);
  395. X        fputc('\n', stderr);
  396. X        exit(1);
  397. X    }
  398. X    if (chdir(path) < 0) {
  399. X        fputs("Strange, can not change directory to ", stderr);
  400. X        fputs(path, stderr);
  401. X        fputc('\n', stderr);
  402. X        exit(1);
  403. X    }
  404. X    if ((nfils = scandir(".", pdot, NULL, alphasort)) < 0) {
  405. X        fputs("Strange, can not scan ", stderr);
  406. X        fputs(path, stderr);
  407. X        fputc('\n');
  408. X        exit(1);
  409. X    }
  410. X    *pfilrep = (REP **)malloc(nfils * sizeof(REP *));
  411. X    return(nfils);
  412. X}
  413. X
  414. X
  415. X
  416. Xstatic int getreps(dot, nfils, from_pat, to_pat, filrep, preps)
  417. X    struct direct *(dot[]);
  418. X    int nfils;
  419. X    char *from_pat, *to_pat;
  420. X    REP *(filrep[]);
  421. X    REP **preps;
  422. X{
  423. X    char *(start[MAXWILD]);
  424. X    int len[MAXWILD];
  425. X    int nreps, i;
  426. X    REP *cur;
  427. X
  428. X    for (*preps = NULL, nreps = 0, i = 0; i < nfils; i++) {
  429. X        if (
  430. X            (*(dot[i]->d_name) != '.' || *from_pat == '.') &&
  431. X            strcmp(dot[i]->d_name, ".") != 0 &&
  432. X            strcmp(dot[i]->d_name, "..") != 0 &&
  433. X            scan(from_pat, dot[i]->d_name, start, len)
  434. X        ) {
  435. X            cur = (REP *)malloc(sizeof(REP));
  436. X            filrep[i] = cur;
  437. X            cur->repname = makerep(to_pat, start, len);
  438. X            cur->ftorep = i;
  439. X            cur->mustdel = -1;
  440. X            cur->nextrep = *preps;
  441. X            cur->status = DO;
  442. X            *preps = cur;
  443. X            nreps++;
  444. X            if (*(cur->repname) == '\0') {
  445. X                fputc('\'', stderr);
  446. X                fputs(dot[i]->d_name, stderr);
  447. X                fputs("' would have to be renamed to empty string.\n",
  448. X                    stderr);
  449. X                fputs("Aborting, no renames done.\n");
  450. X                exit(1);
  451. X            }
  452. X        }
  453. X        else
  454. X            filrep[i] = NULL;
  455. X    }
  456. X    if (nreps == 0) {
  457. X        fputs("No match.\n", stderr);
  458. X        exit(1);
  459. X    }
  460. X    return(nreps);
  461. X}
  462. X
  463. X
  464. Xstatic int scan(pat, s, start1, len1)
  465. X    char *pat, *s, **start1;
  466. X    int *len1;
  467. X{
  468. X    *start1 = 0;
  469. X    while (1) {
  470. X        if (*pat == '*') {
  471. X            pat++;
  472. X            *start1 = s;
  473. X            if (*pat == '\0') {
  474. X                *len1 = strlen(s);
  475. X                return(1);
  476. X            }
  477. X            else {
  478. X                for (*len1=0; !scan(pat, s, start1+1, len1+1); (*len1)++, s++)
  479. X                    if (*s == '\0')
  480. X                        return(0);
  481. X                return(1);
  482. X            }
  483. X        }
  484. X        else if (*pat == '\0')
  485. X            return(*s == '\0');
  486. X        else if (*pat == '?') {
  487. X            if (*s == '\0')
  488. X                return(0);
  489. X            *(start1++) = s;
  490. X            *(len1++) = 1;
  491. X            pat++;
  492. X            s++;
  493. X        }
  494. X        else {
  495. X            if (*pat == '\\') {
  496. X                pat++;
  497. X                if (*pat == '\0')
  498. X                    return(*s == '\0');
  499. X            }
  500. X            if (*pat == *s) {
  501. X                 pat++;
  502. X                s++;
  503. X            }
  504. X            else
  505. X                return(0);
  506. X        }
  507. X    }
  508. X}
  509. X
  510. X
  511. Xstatic char *makerep(pat, start, len)
  512. X    char *pat, **start;
  513. X    int *len;
  514. X{
  515. X    int i, k;
  516. X    char *q, *p, *res;
  517. X    char b[MAXNAMLEN];
  518. X
  519. X    p = b;
  520. X    for ( ; *pat != '\0'; pat++) {
  521. X        if (*pat == '#') {
  522. X            pat++;
  523. X            k = *pat - '1';
  524. X            if (p - b + len[k] > MAXNAMLEN) {
  525. X                fputs("Replacement name too long.\n", stderr);
  526. X                exit(1);
  527. X            }
  528. X            for (i=0, q = start[k]; i < len[k]; i++)
  529. X                *(p++)= *(q++);
  530. X        }
  531. X        else {
  532. X            if (*pat == '\\') {
  533. X                pat++;
  534. X                if (*pat == '\0')
  535. X                    break;
  536. X            }
  537. X            if (p - b + 1 > MAXNAMLEN) {
  538. X                fputs("Replacement name too long.\n", stderr);
  539. X                exit(1);
  540. X            }
  541. X            *(p++)= *pat;
  542. X        }
  543. X    }
  544. X    *(p++) = '\0';
  545. X    res = (char *)malloc((p - b) * sizeof(char));
  546. X    strcpy(res, b);
  547. X    return(res);
  548. X}
  549. X
  550. X
  551. Xstatic checkcollisons(reps, nreps)
  552. X    REP *reps;
  553. X    int nreps;
  554. X{
  555. X    char **repdict;
  556. X    REP *cur;
  557. X    int i;
  558. X
  559. X    repdict = (char **)malloc(nreps * sizeof(char *));
  560. X    for (i = 0, cur = reps; cur != NULL; cur = cur->nextrep)
  561. X        repdict[i++] = cur->repname;
  562. X    qsort(repdict, nreps, sizeof(char *), mycmp);
  563. X    for (i = 0; i < nreps-1; i++)
  564. X        if (strcmp(repdict[i], repdict[i+1]) == 0) {
  565. X            fputs("Two or more files would have to be renamed to '",
  566. X                stderr);
  567. X            fputs(repdict[i], stderr);
  568. X            fputs("'.\n", stderr);
  569. X            fputs("Aborting, no renames done.\n", stderr);
  570. X            exit(1);
  571. X        }
  572. X}
  573. X
  574. X
  575. Xstatic int mycmp(pps1, pps2)
  576. X    char **pps1, **pps2;
  577. X{
  578. X    return(strcmp(*pps1, *pps2));
  579. X}
  580. X
  581. X
  582. Xstatic checkdeletes(reps, dot, filrep, nfils, delstyle)
  583. X    REP *reps;
  584. X    struct direct *(dot[]);
  585. X    REP *(filrep[]);
  586. X    int nfils, delstyle;
  587. X{
  588. X    int recheck, i;
  589. X    REP *cur;
  590. X    char doit, reply[MAXREP];
  591. X
  592. X    do {
  593. X        recheck = 0;
  594. X        for (cur = reps; cur != NULL; cur = cur->nextrep) {
  595. X            if (cur->status == FORGET)
  596. X                continue;
  597. X            if ((i = bsearch(cur->repname, dot, nfils)) >= 0) {
  598. X                if (filrep[i] == NULL && cur->mustdel < 0) {
  599. X                    cur->dofirst = NULL;
  600. X                    if (delstyle == QUIETDEL)
  601. X                        cur->mustdel = i;
  602. X                    else if (delstyle == NODEL) {
  603. X                        cur->status = FORGET;
  604. X                        filrep[cur->ftorep] = NULL;
  605. X                        recheck = 1;
  606. X                    }
  607. X                    else if (delstyle == ABORTDEL) {
  608. X                        fputs(dot[i]->d_name, stderr);
  609. X                        fputs(" would have to be removed.\n", stderr);
  610. X                        fputs("Aborting, no renames done.\n", stderr);
  611. X                        exit(1);
  612. X                    }
  613. X                    else {
  614. X                        fputs(dot[cur->ftorep]->d_name, stderr);
  615. X                        fputs(" -> ", stderr);
  616. X                        fputs(cur->repname, stderr);
  617. X                        fputs(" ; remove old ", stderr);
  618. X                        fputs(dot[i]->d_name, stderr);
  619. X                        fputs("? ", stderr);
  620. X                        for (;;) {
  621. X                            doit = *fgets(reply, MAXREP, stdin);
  622. X                            if (doit ==  'Y' || doit == 'y') {
  623. X                                cur->mustdel = i;
  624. X                                break;
  625. X                            }
  626. X                            else if (doit == 'N' || doit == 'n') {
  627. X                                cur->status = FORGET;
  628. X                                filrep[cur->ftorep] = NULL;
  629. X                                recheck = 1;
  630. X                                break;
  631. X                            }
  632. X                            else
  633. X                                fputs("Yes or No? ", stderr);
  634. X                        }
  635. X                    }
  636. X                }
  637. X                else {
  638. X                    cur->dofirst = filrep[i];
  639. X                    cur->mustdel = -1;
  640. X                }
  641. X            }
  642. X            else {
  643. X                cur->dofirst = NULL;
  644. X                cur->mustdel = -1;
  645. X            }
  646. X        }
  647. X    } while (recheck);
  648. X}
  649. X
  650. X
  651. Xstatic int bsearch(s, dlist, n)
  652. X    char *s;
  653. X    struct direct *(dlist[]);
  654. X    int n;
  655. X{
  656. X    int first, k, last, res;
  657. X
  658. X    for(first = 0, last = n - 1;;) {
  659. X        if (last < first)
  660. X            return(-1);
  661. X        k = (first + last) >> 1;
  662. X        if ((res = strcmp(s, dlist[k]->d_name)) == 0)
  663. X            return(k);
  664. X        if (res < 0)
  665. X            last = k - 1;
  666. X        else
  667. X            first = k + 1;
  668. X    }
  669. X}
  670. X
  671. X
  672. Xstatic char** breakcycles(reps, nreps, dot)
  673. X    REP *reps;
  674. X    int nreps;
  675. X    struct direct *(dot[]);
  676. X{
  677. X    char **tempnames;
  678. X    int tempno;
  679. X    REP *cur, *pred;
  680. X
  681. X    tempnames = (char **)malloc(nreps * sizeof(char *) + 1);
  682. X    tempno = 0;
  683. X    for (cur = reps; cur != NULL; cur = cur->nextrep) {
  684. X        if (cur->status == FORGET)
  685. X            continue;
  686. X        for (pred = cur->dofirst;
  687. X             pred != NULL && pred != cur;
  688. X             pred = pred->dofirst)
  689. X        {
  690. X            if (pred->status != DO) {
  691. X                fputs("Strange error in cycle checking.\n", stderr);
  692. X                exit(1);
  693. X            }
  694. X        }
  695. X        if (pred == cur)
  696. X            if (cur->dofirst == cur)
  697. X                cur->status = FORGET;
  698. X            else {
  699. X                pred = (REP *)malloc(sizeof(REP));
  700. X                tempnames[++tempno] =
  701. X                    (char *)malloc(sizeof(tempprefix) + strlen(cur->repname));
  702. X                strcpy(tempnames[tempno], tempprefix);
  703. X                strcat(tempnames[tempno], cur->repname);
  704. X                pred->repname = cur->repname;
  705. X                pred->ftorep = -tempno;
  706. X                pred->dofirst = cur->dofirst;
  707. X                pred->mustdel = -1;
  708. X                pred->status = DO;
  709. X                pred->nextrep = cur->nextrep;
  710. X                cur->repname = tempnames[tempno];
  711. X                cur->dofirst = NULL;
  712. X                cur->nextrep = pred;
  713. X            }
  714. X    }
  715. X    return(tempnames);
  716. X}
  717. X
  718. X
  719. Xstatic dorenames(reps, dot, tempnames, verbose)
  720. X    REP *reps;
  721. X    struct direct *(dot[]);
  722. X    char *(tempnames[]);
  723. X    int verbose;
  724. X{
  725. X    REP *cur;
  726. X    int skipped;
  727. X    char *fromname;
  728. X
  729. X    do {
  730. X        skipped = 0;
  731. X        for (cur = reps; cur != NULL; cur = cur->nextrep) {
  732. X            if (cur->status == DO) {
  733. X                if (cur->dofirst != NULL && cur->dofirst->status != DONE)
  734. X                    skipped = 1;
  735. X                else {
  736. X                    fromname = (cur->ftorep < 0 ?
  737. X                        tempnames[-(cur->ftorep)] :
  738. X                        dot[cur->ftorep]->d_name);
  739. X                    cur->status = DONE;
  740. X                    if (rename(fromname, cur->repname)) {
  741. X                        fputs("Strange. Can not rename '", stderr);
  742. X                        fputs(fromname, stderr);
  743. X                        fputs("' to '", stderr);
  744. X                        fputs(cur->repname, stderr);
  745. X                        fputs("'\n", stderr);
  746. X                    }
  747. X                    else if (verbose) {
  748. X                        fputs(fromname, stdout);
  749. X                        fputs(" -> ", stdout);
  750. X                        fputs(cur->repname, stdout);
  751. X                        if (cur->mustdel >= 0)
  752. X                            fputs(" (*)", stderr);
  753. X                        fputc('\n', stdout);
  754. X                    }
  755. X                }
  756. X            }
  757. X        }
  758. X    } while (skipped);
  759. X}
  760. SHAR_EOF
  761. if test 11365 -ne "`wc -c < 'ren.c'`"
  762. then
  763.     echo shar: "error transmitting 'ren.c'" '(should have been 11365 characters)'
  764. fi
  765. fi
  766. #    End of shell archive
  767. exit 0
  768.  
  769.